package uplb.ics.cs190.e2d.display;

import java.util.ArrayList;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

import uplb.ics.cs190.e2d.graphics.Image;
import uplb.ics.cs190.e2d.math.Dimension;

public class OpenGLMode implements Display {

	protected Dimension size;
	protected boolean isFullscreen;
	protected boolean usingVsync;
	protected String title;
	
	protected OpenGLGraphics currentGraphics;
	
	public OpenGLMode(Dimension d, String title, boolean fullscreen, boolean vsync) {
		this.size = d;
		this.title = title;
		this.isFullscreen = fullscreen;
		this.usingVsync = vsync;
		
		this.initGraphics();
		this.initGL();
		
		this.currentGraphics = new OpenGLGraphics();
	}
	
	public OpenGLMode(Dimension d, String title, boolean fullscreen) {
		this(d, title, fullscreen, true);
	}
	
	private void initGL() {
		GL11.glEnable(GL11.GL_TEXTURE_2D);
		GL11.glDisable(GL11.GL_DEPTH_TEST);
		
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glLoadIdentity();
		
		GL11.glOrtho(0, this.size.width, this.size.height, 0, -1, 1);
		
		GL11.glEnable(GL11.GL_BLEND);
		GL11.glEnable(GL11.GL_ALPHA);
		GL11.glClearColor(0, 0, 0, 0);
		
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
	}
	
	private void initGraphics() {
		try {
			DisplayMode best = (this.isFullscreen) ? 
					this.getBestDisplayMode(size) : new DisplayMode(
							this.size.width, this.size.height);
					
			if(best == null) {
				throw new Exception();
			}

			org.lwjgl.opengl.Display.setDisplayMode(best);
		} catch(Exception e) {
			
		}
		
		try {
			org.lwjgl.opengl.Display.setTitle(this.title);
			org.lwjgl.opengl.Display.setFullscreen(this.isFullscreen);
			org.lwjgl.opengl.Display.setVSyncEnabled(this.usingVsync);
			org.lwjgl.opengl.Display.create();
		} catch(Exception e) {
			
		}
	}
	
	private DisplayMode getBestDisplayMode(Dimension size) {
		try {
			DisplayMode mode[] = org.lwjgl.opengl.Display.getAvailableDisplayModes();
			
			ArrayList<DisplayMode> modeList = new ArrayList<DisplayMode>();
			for(int i=0; i<mode.length; i++) {
				if(mode[i].getWidth() == size.width
						&& mode[i].getHeight() == size.height) {
					modeList.add(mode[i]);
				}
			}
			
			if(modeList.size() == 0) {
				return null;
			}
			
			return modeList.get(modeList.size()-1);
		} catch(Exception e) {
			return null;
		}
	}
		
	@Override
	public Graphics getBackBuffer() {
		return this.currentGraphics;
	}

	@Override
	public boolean flip() {
		if(org.lwjgl.opengl.Display.isCloseRequested()) {
			// window listener
		} else if(org.lwjgl.opengl.Display.isActive()) {
			org.lwjgl.opengl.Display.update();
		} else {
			if(org.lwjgl.opengl.Display.isVisible() 
					|| org.lwjgl.opengl.Display.isDirty()) {
				org.lwjgl.opengl.Display.update();
			}
		}
		return true;
	}

	@Override
	public void cleanup() {
		try {
			org.lwjgl.opengl.Display.destroy();
		} catch(Exception e) {
			
		}
	}

	@Override
	public Dimension getSize() {
		return this.size;
	}

	@Override
	public Image getWindowIcon() {
		return null;
	}

	@Override
	public String getWindowTitle() {
		return org.lwjgl.opengl.Display.getTitle();
	}

	@Override
	public void setWindowIcon(Image icon) {

	}

	@Override
	public void setWindowTitle(String title) {
		org.lwjgl.opengl.Display.setTitle(title);
	}

	public boolean isFullScreen() {
		return this.isFullscreen;
	}
	
	public boolean setFullScreen(boolean b) {
		if(this.isFullscreen != b) {
			try {
				org.lwjgl.opengl.Display.setFullscreen(b);
			} catch(LWJGLException e) {
				return false;
			}
			
			this.isFullscreen = b;
		}
		
		return true;
	}
	
	public boolean isVSync() {
		return this.usingVsync;
	}
	
	public void setVSync(boolean b) {
		if(this.usingVsync != b) {
			org.lwjgl.opengl.Display.setVSyncEnabled(b);
			this.usingVsync = b;
		}
	}
}